package robot

import (
	"context"
	"sale-admin/config/mysql"
	"sale-admin/internal/app/grpc/client"
	"sale-admin/internal/app/grpc/protoc/devicec"
	"sale-admin/internal/app/grpc/protoc/system_admin"
	"sale-admin/internal/app/web/service/common"
	"sale-admin/internal/dal"
	"sale-admin/internal/dao"
	"sale-admin/internal/define"
	"sale-admin/internal/models"
	"strconv"
	"strings"

	"192.168.1.75/go-pkg/logx"
	"github.com/golang-module/carbon/v2"
	"github.com/samber/lo"
)

type StareCount struct{}

// 客群画像
func (StareCount) StareCountList(ctx context.Context, merchantID string, shopList []string,
	startTime, endTime int64, provinceID, cityID, districtID, locationID, robotID string, page, limit int) (
	res []dao.StareAgeGenderList, count int64, summary dao.StareAgeGenderSummary, err error,
) {
	// 默认今天
	if startTime == 0 && endTime == 0 {
		startTime = carbon.Now().StartOfDay().Timestamp()
		endTime = carbon.Now().EndOfDay().Timestamp()
	}
	var filterRobotID []string
	if robotID != "" {
		filterRobotID = strings.Split(robotID, ",")
	}
	var filterLocation []string
	if locationID != "" {
		filterLocation = strings.Split(locationID, ",")
	}
	// 商户筛选
	var filterMerchants = []string{} // 归属商户
	if merchantID != "1" {
		SystemAdminClient, clientErr := client.GetSystemAdminClient()
		if clientErr != nil {
			return
		}
		// 获取直系商户
		req := &system_admin.FamilyMerchantsReq{
			MerchantId: merchantID,
		}
		rsp, err1 := SystemAdminClient.GetFamilyMerchants(ctx, req)
		if err1 != nil {
			return
		}
		if len(shopList) > 0 {
			filterMerchants = lo.Intersect(rsp.MerchantIds, shopList)
		} else {
			filterMerchants = rsp.MerchantIds
		}
	} else {
		if len(shopList) > 0 {
			filterMerchants = shopList
		}
	}
	DeviceAdminClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		return
	}
	// 机器筛选
	var validRobots = []string{} // 归属机器
	if provinceID != "" || cityID != "" || districtID != "" || locationID != "" {
		req := &devicec.DeviceListReq{
			ProvinceId: provinceID, // 省
			CityId:     cityID,     // 市
			DistrictId: districtID, // 区
		}
		rsp, err2 := DeviceAdminClient.DeviceList(ctx, req)
		if err2 != nil {
			return
		}
		for _, v := range rsp.List {
			if len(filterLocation) > 0 && !lo.Contains(filterLocation, v.LocationId) {
				continue
			}
			if len(filterMerchants) > 0 && !lo.Contains(filterMerchants, v.MerchantId) {
				continue
			}
			if len(filterRobotID) > 0 && !lo.Contains(filterRobotID, v.RobotId) {
				continue
			}
			validRobots = append(validRobots, v.RobotId)
		}
		if len(validRobots) == 0 {
			return
		}
	} else {
		robotList, robotCount, _ := dao.Robot{}.RobotList(ctx, mysql.NewDB(), strings.Join(filterMerchants, ","),
			"", robotID, "", "", "", "", "")
		if robotCount == 0 {
			return
		}
		for _, v := range robotList {
			validRobots = append(validRobots, v.RobotName)
		}
	}

	res, count, summary, err = dao.StareAgeGender{}.StareAnalysis(ctx, dal.Q, strings.Join(filterMerchants, ","),
		strings.Join(validRobots, ","), startTime, endTime, page, limit)
	return
}

type StareFaceCountRatio struct {
	StareCount  int64   `json:"stare_count"`
	StareCount0 int64   `json:"stare_count0"`
	StareCount1 int64   `json:"stare_count1"`
	StareCount2 int64   `json:"stare_count2"`
	StareCount3 int64   `json:"stare_count3"`
	FaceCount   float64 `json:"face_count"`
	FaceCount0  float64 `json:"face_count0"`
	FaceCount1  float64 `json:"face_count1"`
	FaceCount2  float64 `json:"face_count2"`
	FaceCount3  float64 `json:"face_count3"`
	Ratio       float64 `json:"ratio"`
	Ratio0      float64 `json:"ratio0"`
	Ratio1      float64 `json:"ratio1"`
	Ratio2      float64 `json:"ratio2"`
	Ratio3      float64 `json:"ratio3"`
}
type StareFaceCountRes struct {
	Date         string `json:"date"`
	RobotName    string `json:"robot_name"`
	MerchantName string `json:"merchant_name"`
	Province     string `json:"province"`
	City         string `json:"city"`
	District     string `json:"district"`
	Location     string `json:"location"`
	StareFaceCountRatio
}

// 凝视曝光百分比
func (StareCount) StareFaceCountList(ctx context.Context, merchantID string, shopList []string, startTime,
	endTime int64, provinceID, cityID, districtID, locationID, robotID string, page, limit int) (
	res []StareFaceCountRes, count int64, summary StareFaceCountRatio, err error,
) {
	// 默认今天
	if startTime == 0 && endTime == 0 {
		startTime = carbon.Now().StartOfDay().Timestamp()
		endTime = carbon.Now().EndOfDay().Timestamp()
	}
	// 整理参数
	var filterRobotID []string
	if robotID != "" {
		filterRobotID = strings.Split(robotID, ",")
	}
	var filterLocation []string
	if locationID != "" {
		filterLocation = strings.Split(locationID, ",")
	}
	SystemAdminClient, clientErr := client.GetSystemAdminClient()
	if clientErr != nil {
		return
	}
	// 商户筛选
	var filterMerchants = []string{} // 归属商户
	if merchantID != "1" {
		// 获取直系商户
		req := &system_admin.FamilyMerchantsReq{
			MerchantId: merchantID,
		}
		rsp, err1 := SystemAdminClient.GetFamilyMerchants(ctx, req)
		if err1 != nil {
			return
		}
		if len(shopList) > 0 {
			filterMerchants = lo.Intersect(rsp.MerchantIds, shopList)
		} else {
			filterMerchants = rsp.MerchantIds
		}
	} else {
		if len(shopList) > 0 {
			filterMerchants = shopList
		}
	}
	DeviceAdminClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		return
	}
	// 机器筛选
	var validRobotIDs = []string{} // 归属机器
	if provinceID != "" || cityID != "" || districtID != "" || locationID != "" {
		req := &devicec.DeviceListReq{
			ProvinceId: provinceID, // 省
			CityId:     cityID,     // 市
			DistrictId: districtID, // 区
		}
		rsp, err2 := DeviceAdminClient.DeviceList(ctx, req)
		if err2 != nil {
			return
		}
		for _, v := range rsp.List {
			if len(filterLocation) > 0 && !lo.Contains(filterLocation, v.LocationId) {
				continue
			}
			if len(filterMerchants) > 0 && !lo.Contains(filterMerchants, v.MerchantId) {
				continue
			}
			if len(filterRobotID) > 0 && !lo.Contains(filterRobotID, v.RobotId) {
				continue
			}
			validRobotIDs = append(validRobotIDs, v.RobotId)
		}
		if len(validRobotIDs) == 0 {
			return
		}
	} else {
		robotList, robotCount, _ := dao.Robot{}.RobotList(ctx, mysql.NewDB(), strings.Join(filterMerchants, ","),
			"", robotID, "", "", "", "", "")
		if robotCount == 0 {
			return
		}
		for _, v := range robotList {
			validRobotIDs = append(validRobotIDs, v.RobotName)
		}
	}

	// 曝光数据
	start := carbon.CreateFromTimestamp(startTime).ToDateTimeString()
	end := carbon.CreateFromTimestamp(endTime).ToDateTimeString()
	faceCountTotal := dao.FaceCount{}.GetFaceCountTotal(ctx, dal.Q, filterMerchants,
		strings.Join(validRobotIDs, ","), start, end)
	faceCountList, count := dao.FaceCount{}.GetFaceCountList(ctx, dal.Q, filterMerchants,
		strings.Join(validRobotIDs, ","), start, end, define.DAY, 2, page, limit)
	summary = StareFaceCountRatio{}
	if len(faceCountList) == 0 {
		return
	}
	var robotNames []string
	for _, v := range faceCountList {
		if !lo.Contains(robotNames, v.RobotName) {
			robotNames = append(robotNames, v.RobotName)
		}
	}

	// 机器信息
	robotList, _, _ := dao.Robot{}.RobotList(ctx, mysql.NewDB(), "", "", strings.Join(robotNames, ","), "", "", "", "", "")
	var robotMap = make(map[string]*models.MaRobot)
	var merchantIds []string
	for _, v := range robotList {
		robotMap[v.RobotName] = v
		if !lo.Contains(merchantIds, v.MerchantID) {
			merchantIds = append(merchantIds, v.MerchantID)
		}
	}

	// 商户
	merchantReq := &system_admin.MerchantNameReq{
		MerchantIds: merchantIds,
	}
	merchantNameMapRes, err1 := SystemAdminClient.MerchantName(ctx, merchantReq)
	if err1 != nil {
		return
	}
	// 位置
	deviceReq := &devicec.LocationListReq{}
	deviceRes, err := DeviceAdminClient.LocationList(context.Background(), deviceReq)
	var LocationMap = make(map[string]string)
	areaIDList := []string{}
	if deviceRes != nil && deviceRes.Code == 0 && err == nil {
		for _, v := range deviceRes.List {
			LocationMap[v.Id] = v.Name
			areaIDList = append(areaIDList, v.ProvinceId)
			areaIDList = append(areaIDList, v.CityId)
			areaIDList = append(areaIDList, v.DistrictId)
		}
	}
	// GRPC获取省市区名称
	var AreaNameMap = make(map[string]string)
	var req system_admin.AreaLisRequest
	req.AreaIDs = areaIDList
	areaRes, err1 := SystemAdminClient.AreaList(context.Background(), &req)
	if err1 != nil {
		logx.Error(context.Background(), "areas error", logx.Any("res", areaRes), logx.Any("err", err1.Error()))
		return
	}
	for _, v := range areaRes.Areas {
		AreaNameMap[v.ID] = v.Name
	}
	// 写入曝光量数据
	for _, v := range faceCountList {
		item := StareFaceCountRes{}
		item.Date = carbon.Parse(v.Date).ToDateString()
		item.RobotName = v.RobotName
		item.FaceCount = v.FaceCount
		item.FaceCount0 = v.FaceCount0
		item.FaceCount1 = v.FaceCount1
		item.FaceCount2 = v.FaceCount2
		item.FaceCount3 = v.FaceCount3
		if robotInfo, ok := robotMap[v.RobotName]; ok {
			// 商户名称
			if merchantNameMapRes != nil && merchantNameMapRes.MerchantNameMap != nil {
				if merchantName, ok := merchantNameMapRes.MerchantNameMap[robotInfo.MerchantID]; ok {
					item.MerchantName = merchantName
				}
			}
			// 省市区 位置
			locationID := strconv.Itoa(robotInfo.Areas3)
			provinceID := strconv.Itoa(robotInfo.Areas1)
			cityID := strconv.Itoa(robotInfo.Areas2)
			districtID := strconv.Itoa(robotInfo.Areas5)
			if locationName, ok := LocationMap[locationID]; ok {
				item.Location = locationName
			}
			if province, ok := AreaNameMap[provinceID]; ok {
				item.Province = province
			}
			if city, ok := AreaNameMap[cityID]; ok {
				item.City = city
			}
			if district, ok := AreaNameMap[districtID]; ok {
				item.District = district
			}
		}
		res = append(res, item)
	}

	// 凝视数据
	stareCountTotal := dao.StareCount{}.Total(ctx, dal.Q, strings.Join(filterMerchants, ","), strings.Join(validRobotIDs, ","), startTime, endTime)
	stareCountList := dao.StareCount{}.List(ctx, dal.Q, strings.Join(filterMerchants, ","), strings.Join(validRobotIDs, ","),
		startTime, endTime, 0, 0)

	for k, v := range res {
		for _, i := range stareCountList {
			if v.Date == i.CreatedDate && v.RobotName == i.RobotName {
				res[k].StareCount = i.StareCount
				res[k].StareCount0 = i.StareCount0
				res[k].StareCount1 = i.StareCount1
				res[k].StareCount2 = i.StareCount2
				res[k].StareCount3 = i.StareCount3
				if v.FaceCount != 0 {
					res[k].Ratio = common.Decimal(float64(i.StareCount)/v.FaceCount, 4)
				}
				if v.FaceCount0 != 0 {
					res[k].Ratio0 = common.Decimal(float64(i.StareCount0)/v.FaceCount0, 4)
				}
				if v.FaceCount1 != 0 {
					res[k].Ratio1 = common.Decimal(float64(i.StareCount1)/v.FaceCount1, 4)
				}
				if v.FaceCount2 != 0 {
					res[k].Ratio2 = common.Decimal(float64(i.StareCount2)/v.FaceCount2, 4)
				}
				if v.FaceCount3 != 0 {
					res[k].Ratio3 = common.Decimal(float64(i.StareCount3)/v.FaceCount3, 4)
				}
			}
		}
	}

	// 总计 -- 凝视数据
	summary.StareCount = stareCountTotal.StareCount
	summary.StareCount0 = stareCountTotal.StareCount0
	summary.StareCount1 = stareCountTotal.StareCount1
	summary.StareCount2 = stareCountTotal.StareCount2
	summary.StareCount3 = stareCountTotal.StareCount3
	// 总计 -- 曝光量数据
	summary.FaceCount = faceCountTotal.FaceCount
	summary.FaceCount0 = faceCountTotal.FaceCount0
	summary.FaceCount1 = faceCountTotal.FaceCount1
	summary.FaceCount2 = faceCountTotal.FaceCount2
	summary.FaceCount3 = faceCountTotal.FaceCount3
	// 总计 -- 占比
	if summary.FaceCount != 0 {
		summary.Ratio = common.Decimal(float64(summary.StareCount)/summary.FaceCount, 4)
	}
	if summary.FaceCount0 != 0 {
		summary.Ratio0 = common.Decimal(float64(summary.StareCount0)/summary.FaceCount0, 4)
	}
	if summary.FaceCount1 != 0 {
		summary.Ratio1 = common.Decimal(float64(summary.StareCount1)/summary.FaceCount1, 4)
	}
	if summary.FaceCount2 != 0 {
		summary.Ratio2 = common.Decimal(float64(summary.StareCount2)/summary.FaceCount2, 4)
	}
	if summary.FaceCount3 != 0 {
		summary.Ratio3 = common.Decimal(float64(summary.StareCount3)/summary.FaceCount3, 4)
	}
	return
}
